﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GraphosData
{

	public class Graph
	{

		/// <summary>
		/// All nodes in the graph
		/// </summary>
		public IEnumerable<Node> Nodes
		{
			get { return m_personToNode.Values; }
		}

		/// <summary>
		/// Gets the node corresponding with person
		/// </summary>
		/// <param name="person">The person</param>
		/// <returns></returns>
		public Node GetNode(Person person)
		{
			Node node;
			m_personToNode.TryGetValue(person, out node);
			return node;
		}

		/// <summary>
		/// Add a node to the graph using the following Person data
		/// </summary>
		/// <param name="person"></param>
		/// <returns></returns>
		public Node AddNode(Person person)
		{
			Node node;
			if (!m_personToNode.TryGetValue(person, out node))
			{
				node = new Node(person);
				m_personToNode.Add(person, node);
			}
			return node;
		}

		/// <summary>
		/// Add an edge from p1 to p2 with the supplied Relation
		/// </summary>
		/// <param name="p1">The "from" person</param>
		/// <param name="p2">The "to" person</param>
		/// <param name="relation">The relationship between p1 and p2</param>
		public void AddEdge(Person p1, Person p2, Relation relation)
		{
			AddEdge(GetNode(p1), GetNode(p2), relation);
		}

		// add an edge using the nodes
		private void AddEdge(Node n1, Node n2, Relation relation)
		{
			if (n1 == null || n2 == null)
				return;

			n1.AddAdjacentNode(n2, relation);
			n2.AddAdjacentNode(n1, relation);
		}

		// the sorted dictionary mapping persons to nodes
		SortedDictionary<Person, Node> m_personToNode = new SortedDictionary<Person, Node>();
	} 



	/// <summary>
	/// A Node
	/// </summary>
	public class Node : IComparable<Node>
	{

		/// <summary>
		/// Creates a new instance of the Node class
		/// </summary>
		/// <param name="person">The person data for this node</param>
		public Node(Person person)
		{
			m_person = person;
		}

		/// <summary>
		/// Gets the person
		/// </summary>
		public Person Person
		{
			get { return m_person; }
		}

		/// <summary>
		/// Gets all the adjacent nodes to the instance
		/// </summary>
		public IEnumerable<Node> AdjacentNodes
		{
			get { return m_nodeToRelation.Keys; }
		}

		/// <summary>
		/// Gets the relationship between the instance and the supplied node
		/// </summary>
		/// <param name="node">The node which the relationship is to</param>
		/// <returns>A Relation</returns>
		public Relation RelationTo(Node node)
		{
			Relation rel;
			if (!m_nodeToRelation.TryGetValue(node, out rel))
				return Relation.Unknown;
			return rel;
		}

		/// <summary>
		/// Adds an adjacent node to the instance
		/// </summary>
		/// <param name="node">The node to add</param>
		/// <param name="relation">The relationship of the instance with the node</param>
		public void AddAdjacentNode(Node node, Relation relation)
		{
			m_nodeToRelation[node] = relation;
		}

		// override for easy debugging
		public override string ToString()
		{
            return Person.FirstName + " " + Person.LastName;
		}

		private Person m_person;
		private Dictionary<Node, Relation> m_nodeToRelation = new Dictionary<Node, Relation>();



        #region IComparable<Node> Members

        public int CompareTo(Node other)
        {
            return RelationTo(other).CompareTo(other.RelationTo(this));
        }

        #endregion
    } 

}
